#include <netinet/in.h> // for sockaddr_in
#include <sys/types.h>  // for socket
#include <sys/socket.h> // for socket
#include <stdio.h>      // for printf
#include <stdlib.h>     // for exit
#include <string.h>     // for bzero
#include <unistd.h>     //for close
#include <time.h>       //for time_settime
#include <signal.h>     //for SIGEV_THREAD

#include "cJSON.h" //for json

#include <curl/curl.h>

#define dpf
#ifdef dpf
#define dpf(format, ...) printf("FILE: "__FILE__            \
                                ", LINE: %d: " format "\n", \
                                __LINE__, ##__VA_ARGS__)
#else
#define dpf(format, ...)
#endif

struct res_string
{
    char *ptr;
    size_t len;
};

// 设备的基础信息
#define STRLEN 128
struct dev_conf
{
    char server_id[STRLEN]; //服务器地址
    int mod;                //模式 0：常电模式 1：间歇模式
    char cid[STRLEN];
    char sver[STRLEN];
    char pver[STRLEN];
    char pname[STRLEN];
    char cname[STRLEN];
    int dev_signal;
    int dev_takemode;
    int dev_battery;

    int heartbeat;
    char poweron[STRLEN];
    char poweroff[STRLEN];
    char upload[STRLEN];
    int takefreq;
    int picquality;
    char *takelist[STRLEN];
} * global_conf;

// static char cid[] = "A0256BB";
// static char sver[] = "abb5df84";
// static char pver[] = "v1.0.1";
// static char pname[] = "gz-gd";
// static char cname[] = "d1-01-c03";
// static char dev_takelist[] = "[\"[\\\"10:00:00\\\"\", \"\\\"12:30:00\\\"]\"]";
// static int dev_signal = 90;
// static int dev_takemode = 0;
// static int dev_battery = 50;

void *sendBuffer(int client_socket);                   //  收到输入发送buffer 阻塞查询结果
void *sendBuffer_norecv(int client_socket, char *msg); //  发送buffer 不查询结果
void *recvBuffer(int client_socket);                   //  查询接收buffer

void *socket_login(int client_socket);                  //  socket设备登录
void *reply(int client_socket, int index, int command); //  返回任务处理结果
void *heartBeat(int client_socket, char *buf_data);     //  通过sleep循环发送心跳
void *command(int client_socket, char *buf_data);       //  处理平台下发设备指令 0拍照

void *buildWebSocket(char *serverIp); //  建立socket

void init_string(struct res_string *s); // 初始化结构字符串

size_t writefunc(void *ptr, size_t size, size_t nmemb, struct res_string *s);                       // curl 回调存储返回数据
void *curl_form(struct res_string *out, char *serverIp, char *token, char *filename, char *base64); // curl 图片base64表单上传 返回存储在out
void *curl_post(struct res_string *out, char *serverIp, char *route, char *data_str, char *token);  // curl post请求 返回存储在out
void *upload_status(char *serverIp, char *res_login);                                               // http上传设备状态

void *http_login(char *serverIp); // http设备登录

#define SOCKET_PORT 8888
#define HTTP_PORT 9999
#define BUFFER_SIZE 1024

void *socket_login(int client_socket)
{
    cJSON *param = NULL;
    param = cJSON_CreateObject();

    cJSON_AddStringToObject(param, "cid", global_conf->cid);
    cJSON_AddStringToObject(param, "sver", global_conf->sver);
    cJSON_AddStringToObject(param, "pver", global_conf->pver);

    char *data_str = cJSON_PrintUnformatted(param);

    char header_str[] = "login$";
    char end_str[] = "$$";

    char *total_str = (char *)calloc(sizeof(header_str) + strlen(data_str) + sizeof(end_str), sizeof(char));
    strncpy(total_str, header_str, sizeof(header_str));
    strncat(total_str, data_str, strlen(data_str));
    strncat(total_str, end_str, sizeof(end_str));

    sendBuffer_norecv(client_socket, total_str);
    recvBuffer(client_socket);
}

void *reply(int client_socket, int index, int command)
{

    // create json
    cJSON *params = NULL;
    params = cJSON_CreateObject();
    // get data from dev,make global variable
    cJSON_AddNumberToObject(params, "code", 0);
    cJSON_AddNumberToObject(params, "index", index);
    cJSON_AddNumberToObject(params, "command", command);

    char *data_str = cJSON_PrintUnformatted(params);

    char header_str[] = "reply$";
    char end_str[] = "$$";

    char *total_str = (char *)calloc(sizeof(header_str) + strlen(data_str) + sizeof(end_str), sizeof(char));
    strncpy(total_str, header_str, sizeof(header_str));
    strncat(total_str, data_str, strlen(data_str));
    strncat(total_str, end_str, sizeof(end_str));

    dpf("total_str: %s\n", total_str);

    sendBuffer_norecv(client_socket, total_str);
}

void *command(int client_socket, char *buf_data)
{
    cJSON *root = cJSON_Parse(buf_data);
    if (!root)
    {
        dpf("no json\n");
    }

    cJSON *index = cJSON_GetObjectItem(root, "index");
    if (!index)
    {
        dpf("no index!\n");
    }

    cJSON *command = cJSON_GetObjectItem(root, "command");
    if (!command)
    {
        dpf("no command!\n");
    }
    else
    {
        dpf("command : %d\n", command->valueint);
        // 0 设备拍照

        // 成功拍照后回复

        cJSON *param = NULL;
        param = cJSON_CreateObject();

        cJSON_AddNumberToObject(param, "code", 0);
        cJSON_AddStringToObject(param, "msg", "");
        cJSON_AddNumberToObject(param, "index", index->valueint);
        cJSON_AddNumberToObject(param, "command", command->valueint);

        char *data_str = cJSON_PrintUnformatted(param);

        char header_str[] = "reply$";
        char end_str[] = "$$";

        char *total_str = (char *)calloc(sizeof(header_str) + strlen(data_str) + sizeof(end_str), sizeof(char));
        strncpy(total_str, header_str, sizeof(header_str));
        strncat(total_str, data_str, strlen(data_str));
        strncat(total_str, end_str, sizeof(end_str));

        sendBuffer_norecv(client_socket, total_str);
    }

    cJSON *params = cJSON_GetObjectItem(root, "params");
    if (!params)
    {
        dpf("no params!\n");
    }
}

void *recvBuffer(int client_socket)
{
    char recvbuf[BUFFER_SIZE] = {0};

    int length = 0;
    int i = 0;

    length = recv(client_socket, recvbuf, BUFFER_SIZE, 0);

    int len = strlen(recvbuf);
    dpf("Reciev:%s \n len:%d\n", recvbuf, len);
    if (len > 0)
    {
        char *command;
        char *buf_data;
        dpf("getData:%s;len:%d;\n", recvbuf, len);
        char *res = strtok(recvbuf, "$");
        while (res != NULL)
        {
            dpf("i:%d %s\n", i, res);
            if (i == 0)
            {
                command = res;
            };
            if (i == 1)
            {
                buf_data = res;
            };
            ++i;

            res = strtok(NULL, "$");
            if (res == NULL)
            {
                break;
            };
        }

        // 初始化设备 开启心跳请求
        if (strcmp(command, "initial") == 0)
        {
            // make a fork() for heartBeat
            pid_t heartbeat_pid;
            pid_t attended_pid;
            heartbeat_pid = fork();

            if (heartbeat_pid < 0)
            {
                dpf("Fork error");
            }

            if (heartbeat_pid == 0)
            {
                // 开启副进程
                dpf("i am the heartBeat process, my process id is %d\n", getpid());
                while (1)
                {
                    heartBeat(client_socket, &buf_data);
                }
            }
            else
            {
                // 主进程继续 测试时是通过保持sendBuffer里的scanf()阻塞主线程
                dpf("i am the Main process, my process id is %d\n", getpid());
                sendBuffer(client_socket);
            }
        };

        // 配置参数
        if (strcmp(command, "config") == 0)
        {
            dpf("get config: %s\n", buf_data);
            sendBuffer(client_socket);
        }

        // 平台指令
        if (strcmp(command, "command") == 0)
        {
            dpf("get command: %s\n", buf_data);

            // 处理指令后返回
            sendBuffer(client_socket);
        }
    }
    else
    {
        // 测试时通过保持sendBuffer里的scanf()阻塞主线程
        // sendBuffer(client_socket);
    }
}

void *sendBuffer(int client_socket)
{

    char sendbuffer[BUFFER_SIZE];
    bzero(sendbuffer, BUFFER_SIZE);
    dpf("Please Input buffer to Server:\t");
    scanf("%s", sendbuffer);
    char buffer[BUFFER_SIZE];
    bzero(buffer, BUFFER_SIZE);

    // 获取buffer
    int ret = 1;
    ret = strncmp(sendbuffer, "get", sizeof("get"));
    if (ret == 0)
    {
        dpf("get buffer\n");
        recvBuffer(client_socket);
        return (int *)-1;
    };

    strncpy(buffer, sendbuffer, strlen(sendbuffer) > BUFFER_SIZE ? BUFFER_SIZE : strlen(sendbuffer));
    dpf("begin send buffer: %s\n", buffer);
    //向服务器发送buffer中的数据
    send(client_socket, buffer, BUFFER_SIZE, 0);
    dpf("send buffer success\n");

    ret = strcmp(sendbuffer, "exit");
    if (ret == 0)
    {
        dpf("exit\n");
        // close(client_socket);
        shutdown(client_socket, 2);
    };

    recvBuffer(client_socket);
}

void *sendBuffer_norecv(int client_socket, char *msg)
{
    char buffer[BUFFER_SIZE];
    bzero(buffer, BUFFER_SIZE);

    strncpy(buffer, msg, strlen(msg) > BUFFER_SIZE ? BUFFER_SIZE : strlen(msg)); //控制单次最大传输字节数 超过1024字节的传输可能会分批传输

    send(client_socket, buffer, BUFFER_SIZE, 0);
}

void *heartBeat(int client_socket, char *buf_data)
{
    
    cJSON *root = cJSON_Parse(buf_data);
    if (!root)
    {
        dpf("no json\n");
        root = cJSON_CreateObject();
    }

    cJSON *data = cJSON_GetObjectItem(root, "data");
    if (!data)
    {
        dpf("no data!\n");
        data = cJSON_CreateObject();
    }

    cJSON *heartbeat = cJSON_GetObjectItem(data, "heartbeat");
    if (!heartbeat)
    {
        dpf("no heartbeat!\n");
        // 默认参数
        heartbeat = cJSON_CreateNumber(global_conf->heartbeat);
        dpf("default value: %d\n", heartbeat->valueint);
        sleep(10);
    }
    else
    {
        dpf("%d\n", heartbeat->valueint);
        sleep(heartbeat->valueint);
    }

    cJSON *poweron = cJSON_GetObjectItem(data, "poweron");
    if (!poweron)
    {
        dpf("no poweron!\n");
        // 默认参数
        poweron = cJSON_CreateString(global_conf->poweron);
        dpf("default value: %s\n", poweron->valuestring);
    }

    cJSON *poweroff = cJSON_GetObjectItem(data, "poweroff");
    if (!poweroff)
    {
        dpf("no poweroff!\n");
        // 默认参数
        poweroff = cJSON_CreateString(global_conf->poweroff);
        dpf("default value: %s\n", poweroff->valuestring);
    }

    cJSON *upload = cJSON_GetObjectItem(data, "upload");
    if (!upload)
    {
        dpf("no upload!\n");
        // 默认参数
        upload = cJSON_CreateString(global_conf->upload);
        dpf("default value: %s\n", upload->valuestring);
    }

    cJSON *takefreq = cJSON_GetObjectItem(data, "takefreq");
    if (!takefreq)
    {
        dpf("no takefreq!\n");
        // 默认参数
        takefreq = cJSON_CreateNumber(global_conf->takefreq);
        dpf("default value: %d\n", takefreq->valueint);
    }
    else
    {
        dpf("%d\n", takefreq->valueint);
    }

    cJSON *picquality = cJSON_GetObjectItem(data, "picquality");
    if (!picquality)
    {
        dpf("no picquality!\n");
        // 默认参数
        picquality = cJSON_CreateNumber(global_conf->picquality);
        dpf("default value: %d\n", picquality->valueint);
    }

    cJSON *takelist = cJSON_GetArrayItem(data, "takelist");
    if (!takelist)
    {
        dpf("no takelist!\n");
        // 默认参数
        takelist = cJSON_CreateStringArray(global_conf->takelist,2);
        dpf("default value: %s\n", takelist->valuestring);
    }


    // create json
    cJSON *params = NULL;
    params = cJSON_CreateObject();
    // get data from dev,make global variable

    cJSON_AddStringToObject(params, "cid", global_conf->cid);
    cJSON_AddStringToObject(params, "pname", global_conf->pname);
    cJSON_AddStringToObject(params, "cname", global_conf->cname);
    cJSON_AddStringToObject(params, "upload", upload->valuestring);
    cJSON_AddStringToObject(params, "poweron", poweron->valuestring);
    cJSON_AddStringToObject(params, "poweroff", poweroff->valuestring);

    time_t t;
    t = time(NULL);
    int dev_timestamp = time(&t);
    cJSON_AddNumberToObject(params, "timestamp", dev_timestamp);

    cJSON_AddNumberToObject(params, "errcode", 0); //错误码 0为正常
    cJSON_AddNumberToObject(params, "signal", global_conf->dev_signal);
    cJSON_AddNumberToObject(params, "heartbeat", heartbeat->valueint);
    cJSON_AddNumberToObject(params, "takemode", global_conf->dev_takemode);
    cJSON_AddNumberToObject(params, "takefreq", takefreq->valueint);
    cJSON_AddNumberToObject(params, "picquality", picquality->valueint);

    // cJSON *takelist = NULL;
    // takelist = cJSON_CreateArray();
    // cJSON_AddItemToArray(takelist, cJSON_CreateString("10:00:00"));
    // cJSON_AddItemToArray(takelist, cJSON_CreateString("12:30:00"));

    cJSON_AddItemToObject(params, "takelist", takelist);

    // cJSON_AddStringToObject(params, "takelist", dev_takelist);

    char *data_str = cJSON_PrintUnformatted(params);

    char header_str[] = "heartBeat$";
    char end_str[] = "$$";

    char *total_str = (char *)calloc(sizeof(header_str) + strlen(data_str) + sizeof(end_str), sizeof(char));
    strncpy(total_str, header_str, sizeof(header_str));
    strncat(total_str, data_str, strlen(data_str));
    strncat(total_str, end_str, sizeof(end_str));

    dpf("total_str: %s\n", total_str);

    sendBuffer_norecv(client_socket, total_str);
}

void *buildWebSocket(char *serverIp)
{
    dpf("Connecting To %s!\n", serverIp);
    struct sockaddr_in client_addr;
    bzero(&client_addr, sizeof(client_addr));

    client_addr.sin_family = AF_INET;
    client_addr.sin_addr.s_addr = htons(INADDR_ANY);
    client_addr.sin_port = htons(0);
    int client_socket = socket(AF_INET, SOCK_STREAM, 0);

    if (client_socket < 0)
    {
        dpf("Create Socket Failed!\n");
        exit(1);
    }

    //把客户机的socket和客户机的socket地址结构联系起来
    if (bind(client_socket, (struct sockaddr *)&client_addr, sizeof(client_addr)))
    {
        dpf("Client Bind Port Failed!\n");
        exit(1);
    }

    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    if (inet_aton(serverIp, &server_addr.sin_addr) == 0)
    {
        dpf("Server IP Address Error!\n");
        exit(1);
    }
    server_addr.sin_port = htons(SOCKET_PORT);
    socklen_t server_addr_length = sizeof(server_addr);

    //向服务器发起连接,连接成功后client_socket代表了客户机和服务器的一个socket连接
    if (connect(client_socket, (struct sockaddr *)&server_addr, server_addr_length) < 0)
    {
        dpf("Can Not Connect To %s!\n", serverIp);
        exit(1);
    }
    dpf("connect Success!\n");

    // 登录设备
    socket_login(client_socket);
}

void init_string(struct res_string *s)
{
    s->len = 0;
    s->ptr = malloc(s->len + 1);
    if (s->ptr == NULL)
    {
        fprintf(stderr, "malloc() failed\n");
        exit(EXIT_FAILURE);
    }
    s->ptr[0] = '\0';
}

size_t writefunc(void *ptr, size_t size, size_t nmemb, struct res_string *s)
{
    size_t new_len = s->len + size * nmemb;
    s->ptr = realloc(s->ptr, new_len + 1);
    if (s->ptr == NULL)
    {
        fprintf(stderr, "realloc() failed\n");
        exit(EXIT_FAILURE);
    }
    memcpy(s->ptr + s->len, ptr, size * nmemb);
    s->ptr[new_len] = '\0';
    s->len = new_len;

    dpf("s.len %d\n", s->len);
    dpf("s.ptr %s\n", s->ptr);
    return size * nmemb;
}

void *curl_form(struct res_string *out, char *serverIp, char *token, char *filename, char *base64)
{
    CURL *curl;
    CURLcode res;
    res = curl_global_init(CURL_GLOBAL_DEFAULT);
    if (res != CURLE_OK)
    {
        fprintf(stderr, "curl_global_init() failed: %s\n",
                curl_easy_strerror(res));
        return (int *)-1;
    }
    curl = curl_easy_init();
    if (curl)
    {
        init_string(out);

        char url_header[] = "http://";
        char route[] = "/insectconfig/picupload";

        char *URL = (char *)calloc(strlen(serverIp) + strlen(route) + sizeof(url_header), sizeof(char));
        strncpy(URL, url_header, sizeof(url_header));
        strncat(URL, serverIp, strlen(serverIp));
        strncat(URL, route, strlen(route));

        struct curl_slist *hs = NULL;
        hs = curl_slist_append(hs, "Content-Type: multipart/form-data");

        if (sizeof(token) > 1)
        {
            char token_header[] = "token: ";
            char *token_total = (char *)calloc(strlen(token) + sizeof(token_header), sizeof(char));
            strncpy(token_total, token_header, sizeof(token_header));
            strncat(token_total, token, strlen(token));

            hs = curl_slist_append(hs, token_total);
        }

        char pic_header[] = "image/jpeg;\nbase64,";
        char *pic_data = (char *)calloc(strlen(base64) + sizeof(pic_header), sizeof(char));
        strncpy(pic_data, pic_header, sizeof(pic_header));
        strncat(pic_data, base64, strlen(base64));

        struct curl_httppost *formpost = NULL;
        struct curl_httppost *lastptr = NULL;
        curl_formadd(&formpost, &lastptr,
                     CURLFORM_COPYNAME, "name",
                     CURLFORM_COPYCONTENTS, global_conf->cid, CURLFORM_END);
        curl_formadd(&formpost, &lastptr,
                     CURLFORM_COPYNAME, "filename",
                     CURLFORM_COPYCONTENTS, filename, CURLFORM_END);
        curl_formadd(&formpost, &lastptr,
                     CURLFORM_COPYNAME, "Content-Type",
                     CURLFORM_COPYCONTENTS, pic_data, CURLFORM_END);

        curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, hs);
        curl_easy_setopt(curl, CURLOPT_PORT, HTTP_PORT);
        curl_easy_setopt(curl, CURLOPT_URL, URL);
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, out);

        res = curl_easy_perform(curl);
        if (res != CURLE_OK)
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
                    curl_easy_strerror(res));

        curl_easy_cleanup(curl);

        curl_formfree(formpost);

        curl_slist_free_all(hs);
    }
    curl_global_cleanup();
    return (int *)-1;
}

void *curl_post(struct res_string *out, char *serverIp, char *route, char *data_str, char *token)
{
    CURL *curl;
    CURLcode res;
    res = curl_global_init(CURL_GLOBAL_DEFAULT);
    if (res != CURLE_OK)
    {
        fprintf(stderr, "curl_global_init() failed: %s\n",
                curl_easy_strerror(res));
        return (int *)1;
    }
    curl = curl_easy_init();
    if (curl)
    {
        init_string(out);

        char url_header[] = "http://";
        char *URL = (char *)calloc(strlen(serverIp) + strlen(route) + sizeof(url_header), sizeof(char));
        strncpy(URL, url_header, sizeof(url_header));
        strncat(URL, serverIp, strlen(serverIp));
        strncat(URL, route, strlen(route));

        struct curl_slist *hs = NULL;
        hs = curl_slist_append(hs, "Content-Type: application/json");

        if (sizeof(token) > 1)
        {
            char *token_header = (char *)calloc(strlen(token) + 8, sizeof(char));
            strncpy(token_header, "token: ", 8);
            strncat(token_header, token, strlen(token));

            hs = curl_slist_append(hs, token_header);
        }

        curl_easy_setopt(curl, CURLOPT_HTTPHEADER, hs);
        curl_easy_setopt(curl, CURLOPT_PORT, HTTP_PORT);
        curl_easy_setopt(curl, CURLOPT_URL, URL);
        curl_easy_setopt(curl, CURLOPT_POST, 1L);
        curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data_str);
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
        curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writefunc);
        curl_easy_setopt(curl, CURLOPT_WRITEDATA, out);

        res = curl_easy_perform(curl);
        if (res != CURLE_OK)
            fprintf(stderr, "curl_easy_perform() failed: %s\n",
                    curl_easy_strerror(res));

        curl_easy_cleanup(curl);
    }
    curl_global_cleanup();
    return (int *)-1;
}

void *upload_status(char *serverIp, char *res_login)
{
    cJSON *root = cJSON_Parse(res_login);
    if (!root)
    {
        dpf("no json\n");
    }

    cJSON *data = cJSON_GetObjectItem(root, "data");
    if (!data)
    {
        dpf("no data!\n");
    }

    cJSON *heartbeat = cJSON_GetObjectItem(data, "heartbeat");
    if (!heartbeat)
    {
        dpf("no heartbeat!\n");
    }
    else
    {
        dpf("%d\n", heartbeat->valueint);
    }

    cJSON *poweron = cJSON_GetObjectItem(data, "poweron");
    if (!poweron)
    {
        dpf("no poweron!\n");
    }

    cJSON *poweroff = cJSON_GetObjectItem(data, "poweroff");
    if (!poweroff)
    {
        dpf("no poweroff!\n");
    }

    cJSON *upload = cJSON_GetObjectItem(data, "upload");
    if (!upload)
    {
        dpf("no upload!\n");
    }

    cJSON *takefreq = cJSON_GetObjectItem(data, "takefreq");
    if (!takefreq)
    {
        dpf("no takefreq!\n");
    }
    else
    {
        dpf("%d\n", takefreq->valueint);
    }

    cJSON *picquality = cJSON_GetObjectItem(data, "picquality");
    if (!picquality)
    {
        dpf("no picquality!\n");
    }

    cJSON *token = cJSON_GetObjectItem(data, "token");
    if (!token)
    {
        dpf("no token!\n");
    }

    char route[] = "/insectconfig/status";

    // create json
    cJSON *params = NULL;
    params = cJSON_CreateObject();

    // get data from dev param
    cJSON_AddStringToObject(params, "cid", global_conf->cid);
    cJSON_AddStringToObject(params, "pname", global_conf->pname);
    cJSON_AddStringToObject(params, "cname", global_conf->cname);

    time_t t;
    t = time(NULL);
    int dev_timestamp = time(&t);
    cJSON_AddNumberToObject(params, "timestamp", dev_timestamp);

    cJSON_AddNumberToObject(params, "signal", global_conf->dev_signal);
    cJSON_AddNumberToObject(params, "battery", global_conf->dev_battery);
    cJSON_AddNumberToObject(params, "takemode", global_conf->dev_takemode);

    cJSON_AddNumberToObject(params, "heartbeat", heartbeat->valueint);
    cJSON_AddNumberToObject(params, "takefreq", takefreq->valueint);
    cJSON_AddNumberToObject(params, "picquality", picquality->valueint);

    cJSON_AddStringToObject(params, "upload", upload->valuestring);
    cJSON_AddStringToObject(params, "poweron", poweron->valuestring);
    cJSON_AddStringToObject(params, "poweroff", poweroff->valuestring);

    cJSON *takelist = NULL;
    takelist = cJSON_CreateArray();
    cJSON_AddItemToArray(takelist, cJSON_CreateString("10:00:00"));
    cJSON_AddItemToArray(takelist, cJSON_CreateString("12:30:00"));

    cJSON_AddItemToObject(params, "takelist", takelist);
    // cJSON_AddStringToObject(params, "takelist", dev_takelist);

    char *data_str = cJSON_PrintUnformatted(params);

    struct res_string res;

    // 上传设备状态 返回res
    curl_post(&res, serverIp, route, data_str, token->valuestring);
    dpf("res from status : %s\n", res.ptr);

    // 上传抓拍图片
    // memset((void *)&res,0,sizeof(struct res_string));
    // char *filename = "gz-gd_d1-01-c03_A0256DB_2021-12-01-11-19.jpg";

    // // base64图片数据
    // char *base64 = ""

    // curl_form(&res, serverIp, token->valuestring, filename, base64);
}

void *http_login(char *serverIp)
{
    char route[20] = "/insectconfig/login";
    struct res_string res;

    // create json
    cJSON *params = NULL;
    params = cJSON_CreateObject();

    // get data from dev param
    cJSON_AddStringToObject(params, "cid", global_conf->cid);
    cJSON_AddStringToObject(params, "sver", global_conf->sver);
    cJSON_AddStringToObject(params, "pver", global_conf->pver);

    char *data_str = cJSON_PrintUnformatted(params);

    curl_post(&res, serverIp, route, data_str, "");
    dpf("res %s\n", res.ptr);

    upload_status(serverIp, res.ptr);
}

// 提供外调用 确认调用模式 附带初始化参数
int init_mod(struct dev_conf *conf)
{
    // 获取设备基础信息为全局变量 判断开启常电还是间隔模式
    global_conf = conf;

    if (global_conf->mod == 0)
    {
        buildWebSocket(global_conf->server_id);
    }
    else
    {
        http_login(global_conf->server_id);
    }
}

int main(int argc, char **argv)
{

    struct dev_conf conf = {
        .server_id = "47.111.21.190",
        .mod = 0,
        .cid = "A0256BB",
        .sver = "abb5df84",
        .pver = "v1.0.1",
        .pname = "gz-gd",
        .cname = "d1-01-c03",
        .dev_signal = 90,
        .dev_takemode = 0,
        .dev_battery = 50,
        .takelist = {"10:00:00","12:30:00"},
        .heartbeat = 10
    };

    init_mod(&conf);

}
